#ifndef __OM_FATH
#define __OM_FATH

#include <omkernel/type.h>

#define FAT_12 12
#define FAT_16 16
#define FAT_32 32

#define FAT_READ  1
#define FAT_WRITE 2

#define FAT_CLUSTER12(_c) (_c & 0x00000fff ) // 12 bits
#define FAT_CLUSTER16(_c) (_c & 0x0000ffff ) // 16 bits
#define FAT_CLUSTER32(_c) (_c & 0x0fffffff ) // 28 bits (yes..fat 32 is really 28)

#define FAT_FREECLUSTER	       0x0000

#define FAT_12_ENDOFCLUSTER    0x0fff
#define FAT_12_BADCLUSTER      0x0ff7
#define FAT_12_RESERVEDCLUSTER 0x0ff8

#define FAT_16_ENDOFCLUSTER    0xffff
#define FAT_16_BADCLUSTER      0xfff7
#define FAT_16_RESERVEDCLUSTER 0xfff8

#define FAT_32_ENDOFCLUSTER    0x0fffffff
#define FAT_32_BADCLUSTER      0x0ffffff7
#define FAT_32_RESERVEDCLUSTER 0x0ffffff8

#define FAT_ENTRY_DELETED      0xe5

struct __fat16_t
{
	uint8_t  drvNum;
	uint8_t  reserved1;
	uint8_t  bootSig;
	uint32_t volumeID;
	uint8_t  volumeLabel[11];
	uint8_t  fsType[8];
} __attribute__((packed));

struct __fat32_t
{
	uint32_t fatSize;
	uint16_t reserved2;
	uint16_t fsVersion;
	uint32_t rootCluster;
	uint16_t fsInfo;
	uint16_t backupBootRecord;
	uint8_t  reserved3[12];
	uint8_t  drvNum;
	uint8_t  reserved4;
	uint8_t  bootSig;
	uint32_t volumeID;
	uint8_t  volumeLable[11];
	uint8_t  fsType[8];
} __attribute__((packed));

typedef struct _fatBootSector_t fatBootSector_t;
struct _fatBootSector_t
{
	uint8_t  jmpBoot[3];
	uint8_t  oemName[8];
	uint16_t bytesPerSec;
	uint8_t  secPerCluster;
	uint16_t reservedSecCount;
	uint8_t  numFats;
	uint16_t rootEntrys;
	uint16_t totalSectors16;
	uint8_t  media;
	uint16_t sectorsPerFat16;
	uint16_t sectorsPerTrack;
	uint16_t heads;
	uint32_t hidden;
	uint32_t totalSectors32;
	union
	{
		struct __fat16_t fat16;
		struct __fat32_t fat32;
		//uint8_t bootCode[474];
	} type;
} __attribute__((packed));

struct fatAttribute
{
	int readonly:1;
	int hidden:1;
	int system:1;
	int volumelabel:1;
	int directory:1;
	int archive:1;
	int reserved:2;
} __attribute__((packed));

typedef struct fatfs_t
{
	uint8_t  type;          // 12, 16, 32
	uint8_t  fatCount;      // number of fat copies
	uint32_t clusterSize; // blocks to create cluster
	uint32_t blocksize;     // bytes per sector;
	uint32_t fatSize;    // total single fat entries
	uint32_t fatEntries;
	uint32_t fatSectors; 
	uint16_t reservedSectors; // reserved sectors (boot sector)
	uint32_t rootEntries;   // entries per root
	uint32_t hiddenBlocks;  // hidden blocks (mbr, etc)
	uint32_t size;          // total volume size in blocks
	uint32_t rootEntryPos;  // starting block of root
	uint32_t dataStart;     // sector of first cluster
	uint32_t itemCount;     // count of dir items in one block
	uint32_t rootDirCluster; // fat32 only -- independent root...
	struct fatEntry_t *rootDir;
	char *fat;              // hold the whole fat
    char *tableDirt;        // for fats synchronization
	int eof;
} fatfs_t;

#define FAT_SET_TIME(time, h, m, s) \
	(time = ((((s/2) & 0x1f) | ((m & 0x3f) << 5)) | ((h & 0x1f) << 11))) 

#define FAT_SET_DATE(date, d, m, y) \
	(date = (((d & 0x1f) | ((m & 0xf) << 5)) | (((y + 100 - 80) & 0x7f) << 9)))
// fatEntry_t - 32bytes
typedef struct fatEntry_t fatEntry_t;
struct fatEntry_t
{
	uint8_t name[11];
	//uint8_t extension[3];
	union {
		struct fatAttribute bits;
		char value;
	} attribute;
	uint8_t reserved;
	uint8_t ctimeTenth;
	uint16_t ctime;
	uint16_t cdate;
	uint16_t access;
	uint16_t clusterHigh;
	uint16_t time;
	uint16_t date;
	uint16_t cluster;
	uint32_t fileSize;
} __attribute__((packed));

typedef struct fatNode_t
{
	struct fatNode_t *next;
	int id;
	int cluster;
	int size;
	struct fatNode_t *parent; // fat node of parent directory
	struct fatEntry_t *entry;     // entry of parent directory
}fatNode_t;

void initFat(void);
#endif
